package com.zjdiepu.www.xhh;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.diepu.www.client.partner.xhh.enums.PartnerErrorCode;
import com.diepu.www.client.xhh.partner.response.BasePartnerResponse;
import com.zjdiepu.www.config.ClientConfig;
import com.zjdiepu.www.net.HttpClient;
import com.zjdiepu.www.security.base.enums.ResultCode;
import com.zjdiepu.www.security.client.encode.ClientEncryptAndDencryptUtil;
import com.zjdiepu.www.security.client.sign.ClientSignFactory;
import com.zjdiepu.www.security.encode.IValidatableRequest;
import com.zjdiepu.www.security.exception.BasePartnerException;
import com.zjdiepu.www.security.server.core.Partners;
import com.zjdiepu.www.security.sign.ISign;
import com.zjdiepu.www.security.sign.lang.SignUtil;
import com.zjdiepu.www.security.util.CollectionInitUtil;

/**
 * 类描述: 请求鑫合汇 <br/>     
 * 项目名称:diepu-parent-partner <br/> 
 * 类名称:XinHeHuiClient <br/>     
 * 创建人:xiongxiaotun <br/> 
 * 创建时间:2017年8月22日 上午10:23:15  <br/>   
 * 修改人:xiongxiaotun <br/> 
 * 修改时间: 2017年8月22日 上午10:23:15   <br/>  
 * 修改备注:   <br/> 
 * @version V1.0   <br/>
 */
public class XinHeHuiClient {
	/**
	 * 合作伙伴
	 */
	private static final Partners partner = Partners.XIN_HE_HUI;
	/**
	 * 请求前获取参数
	 * @author xiongxiaotun <br/>
	 * @Title preRequestParam  <br/>
	 * @Description 请求前获取参数 <br/>
	 * @param xinHeHuiService XinHeHuiService.APPLY_LOAN
	 * @version V1.0  <br/>
	 * @throws BasePartnerException 
	 */
	public static Map<String, String> preRequestParam(IValidatableRequest request) throws BasePartnerException {
		Map<String, String> params = signEncrypt(request);
		return params;
	}	
	
	/**
	 * 请求前获取URL
	 * @author xiongxiaotun <br/>
	 * @Title preRequestUrl  <br/>
	 * @Description 请求前获取URL <br/>
	 * @param xinHeHuiService XinHeHuiService.APPLY_LOAN
	 * @version V1.0  <br/>
	 * @throws BasePartnerException 
	 */
	public static String preRequestUrl(String xinHeHuiService) throws BasePartnerException {
		if(StringUtils.isBlank(xinHeHuiService)) {
			throw new BasePartnerException(PartnerErrorCode.FAIL_HTTP_SERVICE_EMPTY.getCode(), PartnerErrorCode.FAIL_HTTP_SERVICE_EMPTY.getName());
		}
		String gateWay = ClientConfig.getPartnerGateWay(partner);
		if(StringUtils.isBlank(gateWay)) {
			throw new BasePartnerException(ResultCode.FAIL_HTTP_GATEWAY_EMPTY);
		}
		String url = gateWay + xinHeHuiService;
        try {
        	URL uri = new URL(url);
			url = new URI(uri.getProtocol(), null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), null).toString();
		} catch (URISyntaxException | MalformedURLException e) {
			throw new BasePartnerException(PartnerErrorCode.FAIL_HTTP_SERVICE_ERROR.getCode(), PartnerErrorCode.FAIL_HTTP_SERVICE_ERROR.getName());
		}
		return url;
	}
	
	/**
	 * 请求
	 * @author xiongxiaotun <br/>
	 * @Title request  <br/>
	 * @Description 请求 <br/>
	 * @param url
	 * @param params
	 * @version V1.0  <br/>
	 * @throws BasePartnerException 
	 */
	public static String request(String url, Map<String, String> params) throws BasePartnerException {
		String responseString = HttpClient.postForm(url, params, header());
		if(null == responseString) {
			throw new BasePartnerException(ResultCode.FAIL_HTTP);
		}
		return responseString;
	}
	
	/**
	 * 验证和解析结果
	 * @author xiongxiaotun <br/>
	 * @Title response  <br/>
	 * @Description 验证和解析结果 <br/>
	 * @param parseResponse
	 * @version V1.0  <br/>
	 * @throws BasePartnerException 
	 */
	public static <T extends BasePartnerResponse> T parseResponse(String responseString, Class<T> clazz) throws BasePartnerException {
		JSONObject responseDatas = dencryptValidate(responseString);
		if(null == responseDatas) {
			return null;
		}
		if(null == clazz) {
			//不能出现
			throw new BasePartnerException(999, "必填参数Clazz没有传入");
		}
		T t = responseDatas.toJavaObject(clazz);
		if(null == t) {
			throw new BasePartnerException(ResultCode.FAIL_PARSE);
		}
		t.setResponseMessageEvent(responseString); //不为空
		return t;
	}
	
//	======================公共方法===========================
	/**
	 * 获取请求头
	 * @author xiongxiaotun <br/>
	 * @Title header  <br/>
	 * @Description 获取请求头 <br/>
	 * @return
	 * @version V1.0  <br/>
	 */
	public static Map<String, String> header() {
		Map<String, String> headers = CollectionInitUtil.emptyMap();
		headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
		return headers;
	}
	
	/**
	 * 签名并加密
	 * @author xiongxiaotun <br/>
	 * @Title signEncrypt  <br/>
	 * @Description 签名并加密  <br/>
	 * @param validatableRequest
	 * @return
	 * @throws BasePartnerException
	 * @version V1.0  <br/>
	 */
	public static Map<String, String> signEncrypt(IValidatableRequest validatableRequest) throws BasePartnerException{
		String content = null;
		if(null != validatableRequest) {
			content = JSON.toJSONString(validatableRequest);
			validatableRequest.setRequestMessageEvent(content);
		}
		
		if(null == validatableRequest || !validatableRequest.validate()) {
			throw new BasePartnerException(ResultCode.FAIL_PARAM_EMPTY);
		}
		
		Map<String, Object> params = CollectionInitUtil.emptyMap();
		String signFieldName = ClientConfig.getPartnerSignName(partner);
		SignUtil.getSignMap(params, validatableRequest, validatableRequest.getClass(), signFieldName);
		JSONObject parse = JSON.parseObject(content);
		long currentTimeMillis = System.currentTimeMillis();
		params.put("timestamp", currentTimeMillis);
		parse.put("timestamp", currentTimeMillis);
		boolean partnerSignSwitch = ClientConfig.getPartnerSignSwitch(partner);
		String signName = ClientConfig.getPartnerSignName(partner); //appkey
		if(partnerSignSwitch) {
			ISign sign = ClientSignFactory.getSign(partner);
			String signSecretKey = ClientSignFactory.getSignSecretKey(partner);
			String partnerSignSecretKey = ClientConfig.getPartnerSignSecretKey(partner);
			String signCovenantKeyName = ClientConfig.getPartnerSignCovenantKeyName(partner);
			String generateSign = sign.generateSign(params, signSecretKey, partnerSignSecretKey, signName, signCovenantKeyName, false);
			if(StringUtils.isBlank(generateSign)) {
				throw new BasePartnerException(ResultCode.FAIL_SIGN);
			}
			params.put(signName, generateSign);
			parse.put(signName, generateSign);
		} else {
			params.put(signName, "HMu1H/cmyKDOiHv41Y9lLROuOlOo+PPG8F3/RotRmNc=");
			parse.put(signName, "HMu1H/cmyKDOiHv41Y9lLROuOlOo+PPG8F3/RotRmNc=");
		}
		content = JSON.toJSONString(parse);
		validatableRequest.setRequestMessageEvent(content);
		
		String encryptContent = ClientEncryptAndDencryptUtil.encrypt(content, partner);
		validatableRequest.setRequestMessageEventEncode(encryptContent);
		
		Map<String, String> formParams = CollectionInitUtil.emptyMap();
		formParams.put("access_token", encryptContent);
		return formParams;
	}
	
	/**
	 * 解密并验签
	 * @author xiongxiaotun <br/>
	 * @Title dencryptValidate  <br/>
	 * @Description 解密并验签  <br/>
	 * @param validatableRequest
	 * @return
	 * @throws BasePartnerException
	 * @version V1.0  <br/>
	 */
	public static JSONObject dencryptValidate(String responseString) throws BasePartnerException{
		if(StringUtils.isBlank(responseString)) {
			throw new BasePartnerException(ResultCode.FAIL_HTTP);
		}
		boolean encodeResponseSwitch = ClientConfig.getPartnerEncodeResponseSwitch(partner);
		if(encodeResponseSwitch) {
			responseString = ClientEncryptAndDencryptUtil.dencrypt(responseString, partner);
		}
		JSONObject responseObject = JSON.parseObject(responseString);
		if(null == responseObject || responseObject.isEmpty()) {
			throw new BasePartnerException(ResultCode.FAIL_PARSE);
		}
		boolean signResponseSwitch = ClientConfig.getPartnerSignResponseSwitch(partner);
		if(signResponseSwitch) {
			ISign sign = ClientSignFactory.getSign(partner);
			String signSecretKey = ClientSignFactory.getSignSecretKey(partner);
			String partnerSignSecretKey = ClientConfig.getPartnerSignSecretKey(partner);
			String signName = ClientConfig.getPartnerSignName(partner); //appkey
			String signCovenantKeyName = ClientConfig.getPartnerSignCovenantKeyName(partner);
			if(!sign.verifySign(responseObject, (String)responseObject.get(signName), signSecretKey, partnerSignSecretKey, signCovenantKeyName)) {
				throw new BasePartnerException(ResultCode.FAIL_SIGN_VALIDATE);
			}
		}
		
		if(0 != (Integer)responseObject.get("errcode")) {
			throw new BasePartnerException((Integer)responseObject.get("errcode"), (String)responseObject.get("errmsg"));
		}
		
		JSONObject responseDatas = responseObject.getJSONObject("data");
		return responseDatas;
	}
}
